import constants from '@/constants';
import { BaseService } from '@/core/base.service';
import { HuifuService } from '@/core/huifu.service';
import { UtilService } from '@/core/util.service';
import { PaymentTypeEnum, WalletOrderStatusEnum } from '@/enums';
import { getCode } from '@/utils';
import { InjectQueue, Process, Processor } from '@nestjs/bull';
import { OnModuleInit } from '@nestjs/common';
import { Job, Queue } from 'bull';
import dayjs from 'dayjs';
import Decimal from 'decimal.js';

@Processor('wallet')
export class WalletProcessor extends BaseService implements OnModuleInit {
  constructor(
    @InjectQueue('wallet')
    private readonly walletQueue: Queue,
    private readonly utilService: UtilService,
    private readonly huifuService: HuifuService,
  ) {
    super();
  }

  async onModuleInit() {
    await this.utilService.cleanKeys(`bull:wallet:repeat`);
    if (this.config.get('payment') === PaymentTypeEnum.HUIFU) {
      await this.walletQueue.add('polling', null, {
        repeat: {
          every: 30000,
        },
        jobId: 'wallet-polling',
      });
    }
  }

  @Process('polling')
  async polling() {
    console.log(`${dayjs().format('YYYY-MM-DD HH:mm:ss')} - 汇付开户订单轮询`);
    try {
      const orders = await this.prisma.walletOrder.findMany({
        where: {
          status: WalletOrderStatusEnum.PENDING,
          isDeleted: false,
          createdAt: {
            lte: dayjs().subtract(5, 'minutes').toDate(),
          },
        },
      });
      for (let o of orders) {
        console.log(
          `汇付开户订单 ${o.no} ${dayjs(o.createdAt).format('YYYY-MM-DD HH:mm:ss')}`,
        );
        await this.walletQueue.add('account', {
          no: o.no,
        });
      }
    } catch (e) {
      console.log(e);
    }
  }

  @Process('account')
  async account(job: Job<{ no: string }>) {
    const { no } = job.data;
    await this.handleAccountCallback(no);
  }

  @Process('wallet')
  async wallet(job: Job<{ no: string; date: string; userId: string }>) {
    const { no, date, userId } = job.data;
    await this.handleWalletCallback(no, date, userId);
  }

  private async handleAccountCallback(no: string) {
    const order = await this.prisma.walletOrder.findFirst({
      where: {
        no,
        status: WalletOrderStatusEnum.PENDING,
        isDeleted: false,
      },
    });
    if (!order) return;

    const res = await this.huifuService.qry008({
      order_id: order.no,
      order_date: dayjs(order.createdAt).format('YYYYMMDD'),
      trans_type: '36',
    });

    console.log(
      `汇付开户订单查询 ${dayjs().format('YYYY-MM-DD HH:mm:ss')} - ${order.no} - ${res?.resp_code} - ${res?.resp_desc}`,
    );

    if (res?.resp_code !== 'C00000') {
      if (res?.resp_code === 'S00018') {
        await this.prisma.walletOrder.update({
          where: {
            id: order.id,
          },
          data: {
            status: WalletOrderStatusEnum.CANCELED,
          },
        });
      }
      return;
    }

    console.log(
      `汇付开户订单状态 ${dayjs().format('YYYY-MM-DD HH:mm:ss')} - ${order.no} - ${res.trans_stat}`,
    );

    if (['I', 'P'].includes(res?.trans_stat)) {
      await this.walletQueue.add(
        'account',
        {
          no: order.no,
        },
        {
          delay: dayjs().add(1, 'minutes').diff(dayjs()),
        },
      );
      return;
    }

    if ('S' === res?.trans_stat) {
      await this.prisma.walletOrder.update({
        where: {
          id: order.id,
        },
        data: {
          status: WalletOrderStatusEnum.COMPLETED,
        },
      });
      const date = dayjs();
      const no = date + (await getCode(12));
      const total = new Decimal(order.total).toFixed(2);
      const divRes = await this.huifuService.pay066({
        order_date: date.format('YYYYMMDD'),
        order_id: no,
        org_order_date: dayjs(order.createdAt).format('YYYYMMDD'),
        org_order_id: order.no,
        org_trans_type: this.huifuService.mapPayType(res.trans_type),
        trans_amt: new Decimal(total).toFixed(2),
        share_fee_mode: '1',
        div_details: JSON.stringify([
          {
            riskDivType: '1',
            divCustId: this.config.get('huifu.merCustId'),
            divAcctId: this.config.get('huifu.merAcctId'),
            divAmt: total,
          },
        ]),
      });
      if (divRes?.resp_code === 'C00000') {
        console.log(
          `汇付开户订单分账成功 ${dayjs().format('YYYY-MM-DD HH:mm:ss')} - ${order.no} - ${divRes?.resp_desc}`,
        );
      } else {
        console.log(
          `汇付开户订单分账异常 ${dayjs().format('YYYY-MM-DD HH:mm:ss')} - ${order.no} - ${divRes?.resp_desc}`,
        );
      }
      return;
    }

    await this.prisma.walletOrder.update({
      where: {
        id: order.id,
      },
      data: {
        status: WalletOrderStatusEnum.CANCELED,
      },
    });
  }

  private async handleWalletCallback(no: string, date: string, userId: string) {
    const res = await this.huifuService.qry009({
      order_id: no,
      order_date: date,
      trans_type: '8',
    });

    console.log(
      `开户状态查询 ${dayjs().format('YYYY-MM-DD HH:mm:ss')} - ${no} - ${res?.resp_code} - ${res?.resp_desc}`,
    );

    if (res?.resp_code !== 'C00000') {
      return;
    }

    if (['I', 'P'].includes(res?.trans_stat)) {
      await this.walletQueue.add(
        'wallet',
        {
          no,
          date,
        },
        {
          delay: dayjs().add(1, 'minutes').diff(dayjs()),
        },
      );
      return;
    }

    if ('S' === res?.trans_stat) {
      await this.prisma.user.update({
        where: {
          code: userId,
        },
        data: {
          userCustId: res.user_cust_id,
          acctId: res.acct_id,
        },
      });
      console.log(
        `汇付开户成功 ${dayjs().format('YYYY-MM-DD HH:mm:ss')} - ${no} - ${res?.resp_desc}`,
      );
    }
  }
}
